package org.vacoor.xqq;

import com.google.common.eventbus.Subscribe;
import com.sun.awt.AWTUtilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vacoor.xqq.core.bean.*;
import org.vacoor.xqq.core.http.HttpRequestor;
import org.vacoor.xqq.core.http.Request;
import org.vacoor.xqq.core.http.RequestCallbackAdapter;
import org.vacoor.xqq.core.http.Response;
import org.vacoor.xqq.core.mod.BuddyManager;
import org.vacoor.xqq.core.mod.MessageReceiver;
import org.vacoor.xqq.core.mod.MessageSender;
import org.vacoor.xqq.core.mod.impl.SimpleAuthenticator;
import org.vacoor.xqq.core.mod.impl.SimpleMessageReceiver;
import org.vacoor.xqq.core.msg.EventBusHolder;
import org.vacoor.xqq.core.msg.chatmsg.KickMsg;
import org.vacoor.xqq.core.msg.eventmsg.StatusChangeMsg;
import org.vacoor.xqq.core.msg.handler.PrintMessageHandler;
import org.vacoor.xqq.core.msg.req.ReplyMsg;
import org.vacoor.xqq.core.msg.resp.AvatarMessage;
import org.vacoor.xqq.core.msg.resp.LongNickMessage;
import org.vacoor.xqq.hotkey.OSHotKeyBinder;
import org.vacoor.xqq.hotkey.OSHotKeyManager;
//import org.vacoor.xqq.ui.util.AppTrayIcon;
import org.vacoor.xqq.ui.WindowAutoHide;
import org.vacoor.xqq.ui.comp.trayicon.TrayAnimatedIcon;
import org.vacoor.xqq.ui.dynamictree.*;
import org.vacoor.xqq.ui.comp.tabpane.FlatTabbedPaneUI;
import org.vacoor.xqq.ui.comp.trayicon.AppSysTrayIcon;
import org.vacoor.xqq.ui.comp.tabpane.QuickOpTabbedPane;
import org.vacoor.xqq.ui.util.UIs;
import org.vacoor.xqq.ui.chat.UIBuddyManager;
import org.vacoor.xqq.ui.chat.UIChatManager;
import org.vacoor.xqq.ui.chat.MessageDispatcher;
import org.vacoor.xqq.ui.util.WindowMoveHandler;

import javax.swing.*;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;

/**
 * User: vacoor
 * Date: 10/15/13
 * Time: 9:24 AM
 */
public class Login3 {
    public static final int OS_SHOW_IDENTIFER = OSHotKeyManager.nextIdentifier();
    public static Logger logger = LoggerFactory.getLogger(Login3.class);

    public static final long N = 56268888;  // QQ提醒号码

    //
    public static final String LOGOUT_URL = "http://d.web2.qq.com/channel/logout2";
    public static final String CHANGE_STATE = "http://d.web2.qq.com/channel/change_status2";
    public static final String SELF_INFO = "http://s.web2.qq.com/api/get_self_info2?ui=1382082183537";

    // http://s.web2.qq.com/api/get_self_info2?ui=1382081032671
    // {"retcode":0,"result":{"birthday":{"month":1,"year":1983,"day":1},"face":525,"phone":"","occupation":"","allow":1,"college":"","uin":2213328508,"blood":0,"constel":0,"lnick":"","vfwebqq":"064de7e8a8bf4873638789e9f124edb6123b6c5bc7308de9801e6ccc219c1ae85307be465eb009ca","homepage":"","vip_info":0,"city":"郑州","country":"中国","personal":"","shengxiao":0,"nick":"HelloWorld","email":"","province":"河南","account":2213328508,"gender":"male","mobile":""}}

    /**
     * 状态修改
     *
     * @param newState
     * @param clientId
     * @param psessionId
     */
    public void changeState(Status newState, String clientId, String psessionId) {
        HttpRequestor.getInstance().send(
                new Request(CHANGE_STATE, Request.HttpMethod.GET)
                        .addHeader("Referer", "http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=3")
                        .addParameter("newstatus", newState.getName())
                        .addParameter("clientid", clientId)
                        .addParameter("psessionid", psessionId)
                        .addParameter("ui", Math.random() + ""),

                new RequestCallbackAdapter() {
                    @Override
                    public void onSuccess(Response resp) {
                        try {
                            logger.debug("修改状态, 响应: {}", resp.getContent().asString());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
        );
    }


    /**
     * 登出
     *
     * @param clientId
     * @param psessionId
     * @throws java.util.concurrent.ExecutionException
     *
     * @throws InterruptedException
     */
    public static void logout(long clientId, String psessionId) throws ExecutionException, InterruptedException {
        HttpRequestor.getInstance().send(
                new Request(LOGOUT_URL, Request.HttpMethod.GET)
//                        .addHeader("MsgBody-Type", "application/x-www-form-urlencoded; charset=UTF-8")
                        .addHeader("Referer", "http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=3")
                        .addParameter("clientid", clientId)
                        .addParameter("psessionid", psessionId)
                        .addParameter("ids", "")
                        .addParameter("ui", new Date().getTime() + ""),
                new RequestCallbackAdapter() {
                    @Override
                    public void onSuccess(Response resp) {
                        try {
                            logger.debug("登出, 响应: {}", resp.getContent().asString());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
        ).get();
    }


    public static void main(String[] args) throws Exception {
        UIs.installBestLookAndFeel();
        UIManager.put("TreeUI", CategoryTreeUI.class.getCanonicalName());
        UIManager.put("TabbedPaneUI", FlatTabbedPaneUI.class.getCanonicalName());
//        new JTabbedPane().getUIClassID()

        final String ACCOUNT = "2214963100"; // 必须全小写
        final String PASSWD = "jiushi123";
        logger.info("Starting ...");

        final SimpleAuthenticator authctor = new SimpleAuthenticator(ACCOUNT, PASSWD, Status.HIDDEN);

        // 校验是否需要输入验证码a
        boolean check = authctor.safetyCheck();

        if (check) {
            // 获取验证码
            byte[] imgData = authctor.getCaptcha();
            String verify = (String) JOptionPane.showInputDialog(null, "Please Input Left Captcha", "Captcha", JOptionPane.YES_NO_OPTION, new ImageIcon(imgData), null, null);
            authctor.setVerify(verify);
            logger.debug("input verify: {}", verify);
        }

        AuthcState authcState = authctor.doAuthc();
        logger.warn("登录: {}", authcState.getMsg());
        if (AuthcState.SUCCESS != authcState) {
            HttpRequestor.getInstance().destory();
            return;
        }

        logger.debug("登录成功");

        //String vfwebqq = login.getVfwebqq(ptwebqq, clientId);   //Smart 需要

        // 二次登录
        final ChatToken chatToken = authctor.getChatToken();
        if (chatToken == null) {
        }
        logger.debug("login2 result: {}", chatToken);

        final BuddyManager buddyManager = new BuddyManager(chatToken);

        // 构建好友树 --------------------
        Set<Category> categories = buddyManager.getContacts();
        final Map<Long, Buddy> buddies = new HashMap<Long, Buddy>();

        CategoryNode root = new CategoryNode(-1, "root");
        for (Category c : categories) {
            CategoryNode category = new CategoryNode(c.getIndex(), c.getName());
            root.add(category);
            for (Contact contact : c.getContacts()) {
                Buddy buddy = new Buddy(contact.getId(), contact.getNick(), contact.getMark(), contact.getAdditional(), contact.getAvatar());
                category.add(new BuddyNode(buddy));
                buddies.put(contact.getId(), buddy);
            }
        }

        final NotifyTree tree = new NotifyTree(new DataNodeMonitorTreeModel(root));
//        tree.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
//        new TreeNodeMouseEventListener().bind(tree);

        // 消息接收器
        MessageReceiver msgReceiver = new SimpleMessageReceiver(chatToken);
        msgReceiver.start();

        // 消息发送器
        final MessageSender msgSender = new MessageSender(chatToken);

        // frame
        UIManager.put("ScrollBar.width", 10);
        JScrollPane scrollPane = new JScrollPane(tree);
        scrollPane.setBorder(null);
        scrollPane.setViewportBorder(null);
        scrollPane.setBackground(Color.WHITE);

        final JFrame frame = new JFrame();
//        final JWindow frame = new JWindow();
        frame.setIconImage(new ImageIcon(
                Login3.class.getClassLoader().getResource("images/qq19x19.png")
        ).getImage());
        frame.setTitle(" X-QQ ");
        frame.getContentPane().setBackground(Color.WHITE);
        frame.setUndecorated(true);
        AWTUtilities.setWindowOpaque(frame, false);


        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        /*
        scrollPane.setBorder(
                BorderFactory.createTitledBorder(
                        BorderFactory.createLineBorder(Color.GRAY),
                        "Contacts",
                        TitledBorder.DEFAULT_JUSTIFICATION,
                        TitledBorder.DEFAULT_POSITION,
                        UIs.getBestFont().deriveFont(Font.BOLD, 20),
                        new Color(0x3F88FC)
                )
        );
        */


        final JTabbedPane tabPane = new QuickOpTabbedPane(JTabbedPane.TOP, QuickOpTabbedPane.FILL_TAB_LAYOUT);
        tabPane.setOpaque(true);
        tabPane.setUI(new FlatTabbedPaneUI() {
            @Override
            protected void initDefaults() {
                UIManager.put("TabbedPane.font", UIs.getBestFont());
//                UIManager.put("TabbedPane.tabAreaInsets", new Insets(0, 20, 0, 20)); // 标签区域的 margin
                UIManager.put("TabbedPane.tabAreaInsets", new Insets(0, 0, 0, 0)); // 标签区域的 margin
                UIManager.put("TabbedPane.tabInsets", new Insets(5, 15, 5, 15));  // 标签内容 margin
                UIManager.put("TabbedPane.selectedTabPadInsets", new Insets(0, 0, 0, 0));
                UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0));
                UIManager.put("TabbedPane.selectedForeground", new Color(0xE6E7E9));
//                UIManager.put("TabbedPane.background", new Color(0xFCFEFB)); // 背景色
                UIManager.put("TabbedPane.focus", false);
                UIManager.put("TabbedPane.opaque", false);
                UIManager.put("TabbedPane.tabsOpaque", false);
                UIManager.put("TabbedPane.contentOpaque", false);
                UIManager.put("TabbedPane.tabsOverlapBorder", false);
                UIManager.put("TabbedPane.selected", new Color(0x319ACE)); // 选中标签背景色
            }
        });
        tabPane.setBackground(Color.WHITE);

        tabPane.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
//        frame.setContentPane(tabPane);
        frame.add(tabPane);
        tabPane.addTab("联系人", scrollPane);
        tabPane.addTab("群/讨论组", new JLabel(toVerticalHtml("这个有必要, 但是没有搞"), JLabel.CENTER));
        tabPane.addTab("关于", new JLabel("<html><body><h3>关于</h3><p>擦, Linux 下面为什么没有扣扣</p></body></html>", JLabel.LEFT));

        frame.pack();
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        frame.setLocation(screenSize.width - frame.getWidth() - 50, 50);

        frame.setVisible(true);

        new WindowMoveHandler().bindWindowMoveHanderTo(tabPane);

        try {
            OSHotKeyManager hotKeyManager = OSHotKeyManager.getCurrentOSHotKeyManager();
            if (hotKeyManager == null) {
            }
            OSHotKeyBinder binder = hotKeyManager.getOSHotKeyBinder(OS_SHOW_IDENTIFER);
                // ALT + ESC
            binder.setHotKey(KeyEvent.ALT_MASK, KeyEvent.VK_ESCAPE);

            int showContactIdentifier = OSHotKeyManager.nextIdentifier();
            OSHotKeyBinder buddyTabBinder = hotKeyManager.getOSHotKeyBinder(showContactIdentifier);
        } catch (Throwable e) {
        }


        Object keyLi = new Object() {

            @Subscribe
            public void onToMessage(ReplyMsg msg) {
                msgSender.sendContactMsg(msg);
            }

            @Subscribe
            public void onKickMeg(KickMsg msg) {
                HttpRequestor.getInstance().destory();
                JOptionPane.showMessageDialog(null, "亲, 我被踢出来了, 估计哪个坏蛋在别处登陆了, 在我退出前唯一可以告诉你的就是, 它说:\r\n" + msg.getReason(), "消息", JOptionPane.INFORMATION_MESSAGE);
                System.exit(0);
            }

            @Subscribe
            public void onAvatar(AvatarMessage msg) {
                final Buddy buddy = buddies.get(msg.getUin());
                if (buddy != null && msg.getBytes() != null) {
                    buddy.setAvatar(new ImageIcon(msg.getBytes()));
                }
            }

            @Subscribe
            public void onLongNick(LongNickMessage msg) {
                Buddy buddy = buddies.get(msg.getUin());
                if (buddy != null) {
                    buddy.setAdditional(msg.getLnick());
                }
            }

            @Subscribe
            public void onStatusChange(StatusChangeMsg msg) {
                final Buddy buddy = buddies.get(msg.getUin());
                final Status oldStatus = buddy.getStatus();
                buddy.setClientType(msg.getClientType());
                buddy.setStatus(msg.getStatus());

                MutableTreeNode node = tree.getIdentifiableAndObservableNode(buddy.getId());
                CategoryNode parent = (CategoryNode) node.getParent();
                DefaultTreeModel model = (DefaultTreeModel) tree.getModel();

                if (Status.isOfflineStatus(oldStatus) && !Status.isOfflineStatus(msg.getStatus())) {
                    // 上线, 获取头像, 签名, 并将其移动到最前面
                    buddyManager.getAvatarAsync(msg.getUin(), 1);
                    buddyManager.getPersionalMsgAsync(msg.getUin());
                    model.removeNodeFromParent(node);
                    model.insertNodeInto(node, parent, 0);
                } else if (!Status.isOfflineStatus(oldStatus) && Status.isOfflineStatus(msg.getStatus())) {
                    // 下线, 将其移动到后面
                    model.removeNodeFromParent(node);
                    model.insertNodeInto(node, parent, parent.getOnlineCount());
                }
            }
        };

        EventBusHolder.getEventBus().register(keyLi);
        EventBusHolder.getEventBus().register(new PrintMessageHandler());
        buddyManager.getOnlineContacts();
//        AppTrayIcon.getTrayIcon();
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                int ok = JOptionPane.showConfirmDialog(null, "关闭?", "Close", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
                if ((ok & 1) == 0) {
                    AppSysTrayIcon.getCurrentAppTrayAnimatedIcon().removeToSysTray();
                    System.exit(0);
                }
            }
        });
        UIBuddyManager bm = new UIBuddyManager(tree);
        MessageDispatcher dispatcher = new MessageDispatcher(new UIChatManager(), bm);
        EventBusHolder.getEventBus().register(dispatcher);

        PopupMenu popupMenu = new PopupMenu("X-QQ");
        MenuItem exitMenu = new MenuItem("Exit", new MenuShortcut(KeyEvent.VK_X));
        exitMenu.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                AppSysTrayIcon.getCurrentAppTrayAnimatedIcon().removeToSysTray();
                System.exit(0);
            }
        });
        popupMenu.add("X-QQ");
        popupMenu.addSeparator();
        popupMenu.add(exitMenu);

        TrayAnimatedIcon tray = AppSysTrayIcon.addAppTrayAnimatedIcon(new ImageIcon(Login3.class.getClassLoader().getResource("images/logo.png")).getImage(),
                "Java 的系统托盘不敢恭维呀, 不搞了",
                popupMenu
        );
        tray.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                frame.setVisible(true);
            }
        });
        new WindowMoveHandler().bindWindowMoveHanderTo(tree);
        new WindowAutoHide(frame).setHideDirection(WindowAutoHide.HIDE_DIRECTION_TOP);
//        frame.setSize(400, 100);
    }

    static String toVerticalHtml(String str) {
        StringBuilder frag = new StringBuilder();
        frag.append("<html><body>");
        for(char c : str.toCharArray()) {
            frag.append(c).append("<br />");
        }
        return frag.append("</body></html>").toString();
    }
}
